﻿@page "/pages/products"
@using CleanArchitecture.Blazor.Application.Features.Products.DTOs
@using CleanArchitecture.Blazor.Application.Features.Products.Queries.Export
@using CleanArchitecture.Blazor.Application.Features.Products.Queries.Pagination
@using CleanArchitecture.Blazor.Application.Features.Products.Specifications
@using CleanArchitecture.Blazor.Domain.Common.Enums
@using CleanArchitecture.Blazor.Server.UI.Pages.Products.Components
@using CleanArchitecture.Blazor.Application.Features.Products.Caching
@using CleanArchitecture.Blazor.Application.Features.Products.Commands.AddEdit
@using CleanArchitecture.Blazor.Application.Features.Products.Commands.Delete
@using CleanArchitecture.Blazor.Application.Features.Products.Commands.Import

@attribute [Authorize(Policy = Permissions.Products.View)]
@inject IStringLocalizer<Products> L
@inject BlazorDownloadFileService BlazorDownloadFileService

<PageTitle>@Title</PageTitle>

<!-- Advanced search component -->
<AdvancedSearchProducts TRequest="_productsQuery" OnConditionChanged="OnConditionChanged"></AdvancedSearchProducts>

<MudDataGrid ServerData="@(ServerReload)"
             FixedHeader="true"
             FixedFooter="false"
             @bind-RowsPerPage="_defaultPageSize"
             Loading="@_loading"
             MultiSelection="true"
             @bind-SelectedItems="_selectedItems"
             ColumnResizeMode="ResizeMode.Column"
             Hover="true" @ref="_productsGrid">
    <ToolBarContent>
        <MudStack Row Spacing="0" Class="flex-grow-1" Justify="Justify.SpaceBetween">
            <MudStack Row AlignItems="AlignItems.Start">
                <MudIcon Icon="@Icons.Material.Filled.QrCodeScanner" Size="Size.Large" />
                <MudStack Spacing="0">
                    <MudText Typo="Typo.subtitle2" Class="mb-2">@L[_currentDto.GetClassDescription()]</MudText>
                    <MudEnumSelect Style="min-width:120px"
                                   TEnum="ProductListView"
                                   ValueChanged="OnListViewChanged"
                                   Value="_productsQuery.ListView"
                                   Dense="true"
                                   Label="@L["List View"]">
                    </MudEnumSelect>
                </MudStack>
            </MudStack>
            <MudStack Spacing="0" AlignItems="AlignItems.End">
                <MudToolBar Dense WrapContent="true" Class="py-1 px-0">
                    <MudButton Disabled="@_loading"
                               OnClick="@(() => OnRefresh())"
                               StartIcon="@Icons.Material.Outlined.Refresh">
                        @ConstantString.Refresh
                    </MudButton>
                    @if (_accessRights.Create)
                    {
                        <MudButton StartIcon="@Icons.Material.Outlined.Add"
                                   OnClick="OnCreateProduct">
                            @ConstantString.New
                        </MudButton>
                    }
                    <MudMenu TransformOrigin="Origin.BottomRight"
                             AnchorOrigin="Origin.BottomRight"
                             EndIcon="@Icons.Material.Filled.MoreVert"
                             Label="@ConstantString.More">
                        @if (_accessRights.Create)
                        {
                            <MudMenuItem Disabled="@(_selectedItems.Count != 1)" OnClick="OnCloneProduct">
                                @ConstantString.Clone
                            </MudMenuItem>
                        }
                        @if (_accessRights.Delete)
                        {
                            <MudMenuItem Disabled="@(!(_selectedItems.Count > 0))"
                                         OnClick="OnDeleteSelectedProducts">
                                @ConstantString.Delete
                            </MudMenuItem>
                        }
                        @if (_accessRights.Export)
                        {
                            <MudMenuItem Disabled="@_exporting" OnClick="OnExport">
                                @ConstantString.Export
                            </MudMenuItem>
                            <MudMenuItem Disabled="@_pdfExporting" OnClick="OnExportPDF">
                                @ConstantString.ExportPDF
                            </MudMenuItem>
                        }
                        @if (_accessRights.Import)
                        {
                            <MudMenuItem>
                                <MudFileUpload T="IBrowserFile"
                                               FilesChanged="OnFileImport"
                                               Accept=".xlsx">
                                    <ActivatorContent>
                                        <MudButton Class="pa-0 ma-0"
                                                   Style="font-weight:400;text-transform:none;"
                                                   Variant="Variant.Text"
                                                   Disabled="@_uploading">
                                            @ConstantString.Import
                                        </MudButton>
                                    </ActivatorContent>
                                </MudFileUpload>
                            </MudMenuItem>
                        }
                    </MudMenu>
                </MudToolBar>
                <MudStack Row Spacing="1">
                    @if (_accessRights.Search)
                    {
                        <MudTextField T="string"
                                      ValueChanged="@(s => OnSearch(s))"
                                      Value="@_productsQuery.Keyword"
                                      Placeholder="@ConstantString.Search"
                                      Adornment="Adornment.End"
                                      AdornmentIcon="@Icons.Material.Filled.Search"
                                      IconSize="Size.Small">
                        </MudTextField>
                    }
                </MudStack>
            </MudStack>
        </MudStack>
    </ToolBarContent>
    <Columns>
        <SelectColumn ShowInFooter="false"></SelectColumn>
        <TemplateColumn HeaderStyle="width:60px" Title="@ConstantString.Actions" Sortable="false">
            <CellTemplate>
                @if (_accessRights.Edit || _accessRights.Delete)
                {
                    <MudMenu Icon="@Icons.Material.Filled.Edit"
                             Variant="Variant.Outlined"
                             Size="Size.Small"
                             Dense="true"
                             IconColor="Color.Info"
                             AnchorOrigin="Origin.CenterLeft">
                        @if (_accessRights.Edit)
                        {
                            <MudMenuItem OnClick="@(() => OnEditProduct(context.Item))">
                                @ConstantString.Edit
                            </MudMenuItem>
                        }
                        @if (_accessRights.Delete)
                        {
                            <MudMenuItem OnClick="@(() => OnDeleteProduct(context.Item))">
                                @ConstantString.Delete
                            </MudMenuItem>
                        }
                    </MudMenu>
                }
                else
                {
                    <MudTooltip Text="@ConstantString.NoAllowed" Delay="300">
                        <MudIconButton Variant="Variant.Outlined"
                                       Disabled="true"
                                       Icon="@Icons.Material.Filled.DoNotTouch"
                                       Size="Size.Small"
                                       Color="Color.Surface">
                        </MudIconButton>
                    </MudTooltip>
                }
            </CellTemplate>
        </TemplateColumn>
        <PropertyColumn Property="x => x.Brand" Title="@L[_currentDto.GetMemberDescription(x => x.Brand)]">
            <FooterTemplate>
                @ConstantString.Selected: @_selectedItems.Count
            </FooterTemplate>
        </PropertyColumn>
        <PropertyColumn Property="x => x.Name" Title="@L[_currentDto.GetMemberDescription(x => x.Name)]">
            <CellTemplate>
                <div class="d-flex flex-column">
                    <MudText>@context.Item.Name</MudText>
                    <MudText Typo="Typo.body2" Class="mud-text-secondary">
                        @context.Item.Description
                    </MudText>
                </div>
            </CellTemplate>
        </PropertyColumn>
        <PropertyColumn Property="x => x.Price" Title="@L[_currentDto.GetMemberDescription(x => x.Price)]">
            <FooterTemplate>
                @ConstantString.SelectedTotal: @_selectedItems.Sum(x => x.Price)
            </FooterTemplate>
        </PropertyColumn>
        <PropertyColumn Property="x => x.Unit" Title="@L[_currentDto.GetMemberDescription(x => x.Unit)]" />
    </Columns>
    <NoRecordsContent>
        <MudText>@ConstantString.NoRecords</MudText>
    </NoRecordsContent>
    <LoadingContent>
        <MudText>@ConstantString.Loading</MudText>
    </LoadingContent>
    <PagerContent>
        <MudDataGridPager PageSizeOptions="@(new[] { 10, 15, 30, 50, 100, 500, 1000 })" />
    </PagerContent>
</MudDataGrid>

<style>
    @@import url("https://cdn.jsdelivr.net/npm/@@fancyapps/ui@@5.0.36/dist/fancybox/fancybox.css");

    .fancybox__container {
        --fancybox-bg: rgba(24, 24, 27, 0.85);
        z-index: 9999;
    }
</style>

@code {
    [CascadingParameter] private Task<AuthenticationState> AuthState { get; set; } = default!;
    [CascadingParameter] private UserProfile? UserProfile { get; set; }
    public string? Title { get; private set; }
    private HashSet<ProductDto> _selectedItems = new();
    private MudDataGrid<ProductDto> _productsGrid = default!;
    private ProductDto _currentDto = new();
    private ProductsAccessRights _accessRights = new();
    private bool _loading;
    private bool _uploading;
    private bool _exporting;
    private bool _pdfExporting;
    private int _defaultPageSize = 15;

    private ProductsWithPaginationQuery _productsQuery { get; } = new();

    protected override async Task OnInitializedAsync()
    {
        Title = L[_currentDto.GetClassDescription()];
        _accessRights = await PermissionService.GetAccessRightsAsync<ProductsAccessRights>();
        
    }

    private async Task<GridData<ProductDto>> ServerReload(GridState<ProductDto> state)
    {
        try
        {
            _loading = true;
            _productsQuery.CurrentUser = UserProfile;
            _productsQuery.OrderBy = state.SortDefinitions.FirstOrDefault()?.SortBy ?? "Id";
            _productsQuery.SortDirection = state.SortDefinitions.FirstOrDefault()?.Descending ?? true
                                              ? SortDirection.Descending.ToString()
                                              : SortDirection.Ascending.ToString();
            _productsQuery.PageNumber = state.Page + 1;
            _productsQuery.PageSize = state.PageSize;
            var result = await Mediator.Send(_productsQuery).ConfigureAwait(false);
            return new GridData<ProductDto> { TotalItems = result.TotalItems, Items = result.Items };
        }
        finally
        {
            _loading = false;
        }
    }

    private void OnConditionChanged(string condition)
    {
        InvokeAsync(_productsGrid.ReloadServerData);
    }

    private async Task OnSearch(string text)
    {
        _selectedItems = new HashSet<ProductDto>();
        _productsQuery.Keyword = text;
        await _productsGrid.ReloadServerData();
    }

    private async Task OnListViewChanged(ProductListView listview)
    {
        _productsQuery.ListView = listview;
        await _productsGrid.ReloadServerData();
    }

    private async Task OnRefresh()
    {
        ProductCacheKey.Refresh();
        _selectedItems = new HashSet<ProductDto>();
        _productsQuery.Keyword = string.Empty;
        await _productsGrid.ReloadServerData();
    }

    private async Task ShowProductEditFormDialog(string title, AddEditProductCommand command)
    {
        var parameters = new DialogParameters<ProductFormDialog>
        {
            { x => x.Refresh, () => _productsGrid.ReloadServerData() },
            { x => x._model, command }
        };
        var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.Medium, FullWidth = true };
        var dialog = await DialogService.ShowAsync<ProductFormDialog>(title, parameters, options);
        var state = await dialog.Result;
        if (state is not null && !state.Canceled)
        {
            await _productsGrid.ReloadServerData();
            _selectedItems.Clear();
        }
    }

    private async Task OnCreateProduct()
    {
        var command = new AddEditProductCommand { Pictures = new List<ProductImage>() };
        await ShowProductEditFormDialog(string.Format(ConstantString.CreateAnItem, L["Product"]), command);
    }

    private async Task OnCloneProduct()
    {
        var copy = _selectedItems.First();
        var command = new AddEditProductCommand()
        {
            Brand = copy.Brand,
            Name = copy.Name,
            Description = copy.Description,
            Price = copy.Price,
            Unit = copy.Unit,
            Pictures = copy.Pictures
        };
        await ShowProductEditFormDialog(string.Format(ConstantString.CreateAnItem, L["Product"]), command);
    }

    private async Task OnEditProduct(ProductDto dto)
    {
        var command = Mapper.Map<AddEditProductCommand>(dto);
        await ShowProductEditFormDialog(string.Format(ConstantString.EditTheItem, L["Product"]), command);
    }

    private async Task OnDeleteProduct(ProductDto dto)
    {
        var contentText = string.Format(ConstantString.DeleteConfirmation, dto.Name);
        var command = new DeleteProductCommand(new[] { dto.Id });
        await DialogServiceHelper.ShowDeleteConfirmationDialogAsync(command, ConstantString.DeleteConfirmationTitle, contentText, async () =>
        {
            await InvokeAsync(async () =>
            {
                await _productsGrid.ReloadServerData();
                _selectedItems.Clear();
            });
        });
    }

    private async Task OnDeleteSelectedProducts()
    {
        var contentText = string.Format(ConstantString.DeleteConfirmWithSelected, _selectedItems.Count);
        var command = new DeleteProductCommand(_selectedItems.Select(x => x.Id).ToArray());
        await DialogServiceHelper.ShowDeleteConfirmationDialogAsync(command, ConstantString.DeleteConfirmationTitle, contentText, async () =>
        {
            await InvokeAsync(async () =>
            {
                await _productsGrid.ReloadServerData();
                _selectedItems.Clear();
            });
        });
    }

    private async Task OnExport()
    {
        _exporting = true;
        var request = new ExportProductsQuery
        {
            Brand = _productsQuery.Brand,
            Name = _productsQuery.Name,
            MinPrice = _productsQuery.MinPrice,
            MaxPrice = _productsQuery.MaxPrice,
            Unit = _productsQuery.Unit,
            Keyword = _productsQuery.Keyword,
            ListView = _productsQuery.ListView,
            OrderBy = _productsGrid.SortDefinitions.Values.FirstOrDefault()?.SortBy ?? "Id",
            SortDirection = _productsGrid.SortDefinitions.Values.FirstOrDefault()?.Descending ?? false
                                ? SortDirection.Descending.ToString()
                                : SortDirection.Ascending.ToString(),
            CurrentUser = UserProfile,
            ExportType = ExportType.Excel
        };
        var result = await Mediator.Send(request);
        if (result.Succeeded)
        {
            await BlazorDownloadFileService.DownloadFileAsync($"{L["Products"]}.xlsx", result.Data!, "application/octet-stream");
            Snackbar.Add($"{ConstantString.ExportSuccess}", Severity.Info);
        }
        else
        {
            Snackbar.Add($"{result.ErrorMessage}", Severity.Error);
        }
        _exporting = false;
    }

    private async Task OnExportPDF()
    {
        _pdfExporting = true;
        var request = new ExportProductsQuery
        {
            Brand = _productsQuery.Brand,
            Name = _productsQuery.Name,
            MinPrice = _productsQuery.MinPrice,
            MaxPrice = _productsQuery.MaxPrice,
            Unit = _productsQuery.Unit,
            Keyword = _productsQuery.Keyword,
            ListView = _productsQuery.ListView,
            CurrentUser = UserProfile,
            OrderBy = _productsGrid.SortDefinitions.Values.FirstOrDefault()?.SortBy ?? "Id",
            SortDirection = _productsGrid.SortDefinitions.Values.FirstOrDefault()?.Descending ?? false
                                ? SortDirection.Descending.ToString()
                                : SortDirection.Ascending.ToString(),
            ExportType = ExportType.PDF
        };
        var result = await Mediator.Send(request);
        if (result.Succeeded)
        {
            await BlazorDownloadFileService.DownloadFileAsync($"{L["Products"]}.pdf", result.Data!, "application/octet-stream");
            Snackbar.Add($"{ConstantString.ExportSuccess}", Severity.Info);
        }
        else
        {
            Snackbar.Add($"{result.ErrorMessage}", Severity.Error);
        }
        _pdfExporting = false;
    }

    private async Task OnFileImport(IBrowserFile file)
    {
        _uploading = true;
        var stream = new MemoryStream();
        await file.OpenReadStream(GlobalVariable.MaxAllowedSize).CopyToAsync(stream);
        var command = new ImportProductsCommand(file.Name, stream.ToArray());
        var result = await Mediator.Send(command);
        if (result.Succeeded)
        {
            await _productsGrid.ReloadServerData();
            Snackbar.Add($"{ConstantString.ImportSuccess}", Severity.Info);
        }
        else
        {
            foreach (var msg in result.Errors)
            {
                Snackbar.Add($"{msg}", Severity.Error);
            }
        }
        _uploading = false;
    }
}
